﻿using System.Collections;
using System.Text;
using Basic.FormCollect;
using Basic.FormModel.Column;
using Basic.FormModel.DB;
using Basic.FormModel.Form;
using Basic.FormModel.Group;
using Basic.FormRemoteModel;
using Basic.FormRemoteModel.Column.Model;
using Basic.FormRemoteModel.UserForm.Model;
using Basic.UserFormService.Interface;
using Basic.UserFormService.Model;
using WeDonekRpc.CacheClient.Interface;
using WeDonekRpc.Helper;

namespace Basic.UserFormService.lmpl
{
    internal class UserFormBodyService : IUserFormBodyService
    {
        private readonly ICustomFormCollect _Form;
        private readonly ICustomTableCollect _Table;
        private readonly ITableGroupCollect _TableGroup;
        private readonly ITableColumnCollect _TableColumn;
        private readonly ICacheController _Cache;
        public UserFormBodyService ( ICustomFormCollect form,
            ICustomTableCollect table,
            ITableGroupCollect tableGroup,
            ICacheController cache,
            ITableColumnCollect tableColumn )
        {
            this._Cache = cache;
            this._Form = form;
            this._Table = table;
            this._TableGroup = tableGroup;
            this._TableColumn = tableColumn;
        }
        private TableColumnBase[] _columns;
        private TableGroupBase[] _groups;

        public FormBodyDto Get ( long formId )
        {
            string key = string.Concat("FormBody_", formId);
            if ( !this._Cache.TryGet(key, out FormBodyDto dto) )
            {
                dto = this._Get(formId);
                _ = this._Cache.Set(key, dto, DateTime.Now.AddDays(1));
            }
            return dto;
        }
        private List<long> _dicId = null;
        private List<long> _treeDicId = null;
        private Dictionary<long, Dictionary<string, string>> _items;
        private FormBodyDto _Get ( long formId )
        {
            FormBase form = this._Form.Get<FormBase>(formId);
            FormBodyDto body = new FormBodyDto
            {
                FormShow = form.FormShow,
                FormId = form.Id,
                FormName = form.FormName
            };
            DBCustomTable[] tables = this._Table.GetsByFormId<DBCustomTable>(formId);
            if ( tables.IsNull() )
            {
                return body;
            }
            this._columns = this._TableColumn.GetsByFormId<TableColumnBase>(formId);
            if ( this._columns.IsNull() )
            {
                return body;
            }
            if ( tables.IsExists(c => c.TableType == FormTableType.多行列表) )
            {
                this._groups = this._TableGroup.GetsByFormId<TableGroupBase>(formId);
            }
            this._dicId = new List<long>();
            this._treeDicId = new List<long>();
            this._items = new Dictionary<long, Dictionary<string, string>>();
            body.Table = tables.OrderBy(a => a.Sort).Select(this._FormatTable).ToArray();
            body.StateControl = new Dictionary<long, FormStateControl>();
            body.DefState = new Dictionary<long, FormStateControl>();
            body.Formula = this._columns.Convert(a => a.Formula != null, a =>
            {
                ColFormulaVar[] vars = this._InitFormula(a.Formula, out string formula);
                return new ColFormula
                {
                    Formula = formula,
                    Name = a.ColName,
                    VarCol = vars,
                    TableId = a.TableId,
                    DataType = a.DataType,
                    ColId = a.Id,
                };
            });
            body.DicId = this._dicId.Distinct().ToArray();
            body.TreeDicId = this._treeDicId.Distinct().ToArray();
            this._treeDicId.Clear();
            this._dicId.Clear();
            body.StateFormula = this._columns.Convert(a => a.StateFormula != null, a =>
            {
                body.StateControl.Add(a.Id, a.StateControl);
                body.DefState.Add(a.Id, a.DefState);
                ColFormulaVar[] vars = this._InitFormula(a.StateFormula, out string formula);
                return new ColFormula
                {
                    Formula = formula,
                    Name = a.ColName,
                    VarCol = vars,
                    TableId = a.TableId,
                    DataType = a.DataType,
                    ColId = a.Id,
                };
            });
            body.StateDicId = this._dicId.Distinct().ToArray();
            body.TreeStateDicId = this._treeDicId.Distinct().ToArray();
            body.Items = this._items;
            return body;
        }
        private ColFormulaVar[] _InitFormula ( ColumnFormula obj, out string formula )
        {
            if ( obj.VarCol.IsNull() )
            {
                formula = obj.Formula;
                return null;
            }
            StringBuilder str = new StringBuilder();
            string[] rows = obj.Formula.Split('\n');
            Dictionary<long, ColFormulaVar> dic = new Dictionary<long, ColFormulaVar>();
            int index = 0;
            rows.ForEach(( row, i ) =>
            {
                FormulaVar[] vars = obj.VarCol.Where(c => c.From.Line == i).OrderBy(c => c.From.Ch).ToArray();
                if ( !vars.IsNull() )
                {
                    int begin = 0;
                    vars.ForEach(c =>
                    {
                        if ( !dic.TryGetValue(c.ColId, out ColFormulaVar var) )
                        {
                            TableColumnBase col = this._columns.Find(a => a.Id == c.ColId);
                            var = new ColFormulaVar
                            {
                                ColId = c.ColId,
                                TableId = c.TableId,
                                Name = col.ColName,
                                FuncType = col.FuncType,
                                DataType = col.DataType,
                                Key = PublicDataDic.Letter[index % 26] + ( index < 26 ? string.Empty : ( index / 26 ).ToString() ),
                                DefValue = col.DefaultVal
                            };
                            if ( col.ColType == ControlType.Customize && ( col.FuncType == DataFuncType.树形字典 || col.FuncType == DataFuncType.字典项 ) )
                            {
                                Dictionary<string, object> dic = col.ControlSet.Json<Dictionary<string, object>>();
                                if ( dic.TryGetValue("dicId", out object val) )
                                {
                                    var.DicId = Convert.ToInt64(val);
                                    if ( col.FuncType == DataFuncType.树形字典 )
                                    {
                                        this._treeDicId.Add(var.DicId.Value);
                                    }
                                    else
                                    {
                                        this._dicId.Add(var.DicId.Value);
                                    }
                                }
                            }
                            else if ( col.ColType == ControlType.Select || col.ColType == ControlType.Checkbox || col.ColType == ControlType.Radio )
                            {
                                if ( !this._items.ContainsKey(col.Id) )
                                {
                                    Dictionary<string, object> dic = col.ControlSet.Json<Dictionary<string, object>>();
                                    if ( dic.TryGetValue("items", out object obj) )
                                    {
                                        IList list = obj as IList;
                                        Dictionary<string, string> items = new Dictionary<string, string>();
                                        foreach ( IDictionary<string, object> i in list )
                                        {
                                            object k = i["value"];
                                            items.Add(Convert.ToString(i["text"]), k == null ? null : Convert.ToString(k));
                                        }
                                        this._items.Add(c.ColId, items);
                                    }
                                }
                            }
                            index++;
                            dic.Add(c.ColId, var);
                        }
                        int t = c.From.Ch;
                        if ( t != 0 )
                        {
                            int tlen = t - begin;
                            _ = str.Append(row.Substring(begin, tlen));
                            begin += tlen;
                        }
                        int len = c.To.Ch - c.From.Ch;
                        _ = str.Append(var.Key);
                        begin += len;
                    });
                    if ( begin != row.Length )
                    {
                        _ = str.Append(row.Substring(begin));
                    }
                }
            });
            formula = str.ToString();
            return dic.Values.ToArray();
        }
        private FormColumnDto _FormatColumn ( TableColumnBase col )
        {
            return new FormColumnDto
            {
                Key = col.Id,
                Label = col.ColTitle,
                Allias = col.ColAliasName,
                Sort = col.Sort.ToString().PadLeft(2, '0'),
                Column = new UserColumnSet
                {
                    Name = col.ColName,
                    DefaultVal = col.DefaultVal,
                    ColSpan = col.ColSpan,
                    IsLabel = col.IsLabel,
                    ControlSet = col.ControlSet.IsNull() ? null : col.ControlSet.Json<Dictionary<string, object>>(),
                    ColType = col.ColType,
                    FuncType = col.FuncType,
                    EditControl = col.EditControl,
                    Description = col.Description,
                    FiexdType = col.FiexdType,
                    Align = col.Align,
                    IsMergeRow = col.IsMergeRow,
                    IsNotNull = col.IsNotNull,
                    ValidateRule = col.ValidateRule,
                    Width = col.Width
                }
            };
        }
        private FormColumnDto _FormatColumn ( TableColumnBase col, string sort )
        {
            FormColumnDto t = this._FormatColumn(col);
            t.Sort = sort + "_" + t.Sort;
            return t;
        }
        private FormTableDto _FormatTable ( DBCustomTable a )
        {
            FormTableDto table = new FormTableDto
            {
                Id = a.Id,
                ColNum = a.ColNum,
                IsHidden = a.IsHidden,
                LabelWidth = a.LabelWidth,
                TableType = a.TableType,
                Title = a.Title,
                TableSet = a.TableSet,
                SourceKey = a.SourceKey,
                SourceSet = a.SourceSet,
                LabelPosition = a.LabelPosition
            };
            TableColumnBase[] cols = this._columns.FindAll(a => a.TableId == table.Id);
            if ( cols.Length == 0 )
            {
                return table;
            }
            else if ( a.TableType == FormTableType.单一表单 )
            {
                table.Columns = cols.OrderBy(a => a.Sort).Select(this._FormatColumn).ToArray();
            }
            else
            {
                table.MergeCol = cols.Convert(c => c.IsMergeRow, c => c.ColName);
                TableGroupBase[] gList = this._groups.FindAll(c => c.TableId == a.Id && c.ParentId == 0);
                List<FormColumnDto> tList = cols.Where(c => c.GroupId == 0).Select(a => this._FormatColumn(a, a.Sort.ToString().PadLeft(3, '0'))).ToList();
                gList.ForEach(a =>
                {
                    this._InitColumn(a, a.Sort.ToString().PadLeft(3, '0'), tList);
                });
                table.Columns = tList.OrderBy(c => c.Sort).ToArray();
            }
            return table;
        }
        private void _InitColumn ( TableGroupBase prt, string sort, List<FormColumnDto> list )
        {
            TableColumnBase[] gcols = this._columns.FindAll(c => c.GroupId == prt.Id);
            TableGroupBase[] children = this._groups.FindAll(c => c.ParentId == prt.Id);
            if ( gcols.IsNull() && children.IsNull() )
            {
                return;
            }
            if ( prt.IsHidden )
            {
                gcols.ForEach(c =>
                {
                    list.Add(this._FormatColumn(c, sort));
                });
                children.ForEach(a =>
                {
                    string s = sort + "_" + a.Sort.ToString().PadLeft(3, '0');
                    this._InitColumn(a, s, list);
                });
            }
            else
            {
                FormColumnDto col = new FormColumnDto
                {
                    Label = prt.GroupName,
                    Key = prt.Id,
                    Sort = sort
                };
                List<FormColumnDto> child = new List<FormColumnDto>();
                if ( gcols.Length > 0 )
                {
                    gcols.ForEach(c =>
                    {
                        child.Add(this._FormatColumn(c));
                    });
                }
                children.ForEach(a =>
                {
                    this._InitColumn(a, a.Sort.ToString().PadLeft(3, '0'), child);
                });
                col.Children = child.OrderBy(a => a.Sort).ToArray();
                list.Add(col);
            }
        }
    }
}
